package de.hska.pwmanager.controller;

import static de.hska.pwmanager.validation.ValidationUtils.isNullOrEmpty;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import de.hska.pwmanager.controller.errors.ValidationError;
import de.hska.pwmanager.controller.errors.ValidationException;
import de.hska.pwmanager.persistence.model.PasswordData;
import de.hska.pwmanager.persistence.model.PasswordUserHash;
import de.hska.pwmanager.persistence.model.User;
import de.hska.pwmanager.persistence.model.dao.PasswordCategoryDao;
import de.hska.pwmanager.persistence.model.dao.PasswordDataDao;
import de.hska.pwmanager.persistence.model.dao.PasswordUserHashDao;
import de.hska.pwmanager.persistence.model.dao.UserDao;
import de.hska.pwmanager.transfer.model.PasswordDataTransfer;
import de.hska.pwmanager.transfer.model.PasswordUserHashTransfer;

@Controller
@RequestMapping(value = "passwords")
public class PasswordController extends AbstractController implements IPasswordController {
	@Autowired
	private UserDao userDao;
	@Autowired
	private PasswordCategoryDao categoryDao;
	@Autowired
	private PasswordDataDao passwordDataDao;
	@Autowired
	private PasswordUserHashDao passwordUserHashDao;
	@Autowired
	private LoginController loginController;

	public List<PasswordData> readAll() {
		User curUser = this.loginController.getLoggedInUser();
		List<PasswordData> datas = this.getUserPasswords(curUser);
		return datas;
	}

	public List<PasswordData> getUserPasswords(User curUser) {
		List<PasswordData> passwordDatas = new ArrayList<PasswordData>();
		for (PasswordData passwordData : this.passwordDataDao.readAll()) {
			for (PasswordUserHash passwordUserHash : passwordData
					.getPasswordUserHashs()) {
				if (passwordUserHash.getUser().equals(curUser)) {
					PasswordData pwData = new PasswordData()
							.setId(passwordData.getId())
							.setNotes(passwordData.getNotes())
							.setPasswordCategory(
									passwordData.getPasswordCategory())
							.setTitle(passwordData.getTitle())
							.setUsername(passwordData.getUsername());
					pwData.getPasswordUserHashs().add(passwordUserHash);
					passwordDatas.add(pwData);
					break;
				}
			}
		}
		return passwordDatas;
	}

	public void createOrUpdate(
			@RequestBody PasswordDataTransfer toCreateOrUpdate)
			throws ValidationException {
		this.validate(toCreateOrUpdate);
		PasswordData morphed = toCreateOrUpdate.morph();
		PasswordData passwordData = this.passwordDataDao.save(morphed);
		for (PasswordUserHashTransfer passwordUserHash : toCreateOrUpdate
				.getPasswordUserHashs()) {
			PasswordUserHash savedHash = this.passwordUserHashDao
					.save(passwordUserHash.morph());
			passwordData.getPasswordUserHashs().add(savedHash);
		}
		this.passwordDataDao.save(passwordData);
	}

	public void delete(@PathVariable(value = "id") Long primaryKey) throws ValidationException {
		ValidationException validationException = new ValidationException();
		PasswordData passwordData = this.readByPK(primaryKey);
		for (PasswordUserHash passwordUserHash : passwordData.getPasswordUserHashs()) {
			if(passwordUserHash.getUser().equals(this.loginController.getLoggedInUser())) {
				this.passwordDataDao.delete(passwordData);
				return;
			}
		}
		validationException.addError(new ValidationError("","You're not allowed to delete this password"));
		validationException.throwMe();
	}

	public void validate(PasswordDataTransfer toValidate)
			throws ValidationException {
		ValidationException validationException = new ValidationException();
		if (isNullOrEmpty(toValidate.getTitle())) {
			validationException.addError(new ValidationError("title",
					"Title field can't be empty"));
		} else {
			if (toValidate.getId() == null) {
				if (this.passwordDataDao.findByTitle(toValidate.getTitle())
						.size() > 0) {
					validationException.addError(new ValidationError("title",
							"A password with that title already exists"));
				}
			} else {
				if(this.passwordDataDao.findByTitleAndIdNot(toValidate.getTitle(),toValidate.getId()).size()>0) {
					validationException.addError(new ValidationError("title",
					"A password with that title already exists"));
				}
			}
		}

		if (!this.categoryDao.exists(toValidate.getPasswordCategoryID())) {
			validationException.addError(new ValidationError("categoryID",
					"Selected category doesn't exist on the server side"));
		}
		for(PasswordUserHashTransfer passwordUserHashTransfer : toValidate.getPasswordUserHashs()) {
			validationException.addAll(this.validateUserHash(passwordUserHashTransfer));
		}
		validationException.throwMe();
	}

	private ValidationException validateUserHash(PasswordUserHashTransfer passwordUserHashTransfer) {
		ValidationException validationException = new ValidationException();
		if(!this.userDao.exists(passwordUserHashTransfer.getUserID())) {
			validationException.addError(new ValidationError("userID" ,"Selected user doesn't exist in database"));
		}
		return validationException;
	}
	
	public @ResponseBody
	PasswordData readByPK(@PathVariable(value = "id") Long pk) {
		return this.passwordDataDao.readByPrimaryKey(pk);
	}

	public void delete(List<PasswordData> entities) throws ValidationException {
		for (PasswordData toDelete : entities) {
			this.delete(toDelete.getId());
		}

	}

}
